package com.example.ccj.u.tengxun.cos;

import android.content.Context;
import android.util.Pair;

import androidx.annotation.Nullable;

import com.example.ccj.u.GsonUtils;
import com.example.ccj.u.LogUtils;
import com.example.ccj.u.media.Picture;
import com.example.ccj.u.server.MyObserver;
import com.example.ccj.u.server.Result;
import com.example.ccj.u.server.test.TestImpl;
import com.example.ccj.u.tengxun.CosSts;
import com.luck.picture.lib.entity.LocalMedia;
import com.tencent.cos.xml.CosXmlService;
import com.tencent.cos.xml.CosXmlServiceConfig;
import com.tencent.cos.xml.exception.CosXmlClientException;
import com.tencent.cos.xml.exception.CosXmlServiceException;
import com.tencent.cos.xml.listener.CosXmlProgressListener;
import com.tencent.cos.xml.listener.CosXmlResultListener;
import com.tencent.cos.xml.model.CosXmlRequest;
import com.tencent.cos.xml.model.CosXmlResult;
import com.tencent.cos.xml.model.bucket.GetBucketRequest;
import com.tencent.cos.xml.model.bucket.GetBucketResult;
import com.tencent.cos.xml.model.object.CopyObjectRequest;
import com.tencent.cos.xml.model.object.DeleteObjectRequest;
import com.tencent.cos.xml.model.object.DeleteObjectResult;
import com.tencent.cos.xml.model.tag.InitiateMultipartUpload;
import com.tencent.cos.xml.model.tag.ListBucket;
import com.tencent.cos.xml.transfer.COSXMLCopyTask;
import com.tencent.cos.xml.transfer.COSXMLUploadTask;
import com.tencent.cos.xml.transfer.InitMultipleUploadListener;
import com.tencent.cos.xml.transfer.TransferConfig;
import com.tencent.cos.xml.transfer.TransferManager;
import com.tencent.cos.xml.transfer.TransferState;
import com.tencent.cos.xml.transfer.TransferStateListener;
import com.tencent.qcloud.core.auth.BasicLifecycleCredentialProvider;
import com.tencent.qcloud.core.auth.QCloudLifecycleCredentials;
import com.tencent.qcloud.core.auth.SessionQCloudCredentials;
import com.tencent.qcloud.core.common.QCloudClientException;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.android.schedulers.AndroidSchedulers;

public class COS extends BasicLifecycleCredentialProvider {

    public static String COS_REGION = "ap-beijing";

    public static CosSts cosSts;
    private static COS cos;


    public static synchronized COS getInstance() {
        synchronized (COS.class) {
            if (cos == null) {
                cos = new COS();
            }
            return cos;
        }
    }

    public void getSts(){
        TestImpl.getInstance().getCosSTS().subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new MyObserver<Result>() {
                    @Override
                    public void onNext(Result result) {
                        cosSts = GsonUtils.fromJson(result.getData(), CosSts.class);
                    }
                });
    }

    /**
     * 获取文件列表
     * @param context
     * @param cosFormIcon
     */
    public void getAllFile(Context context,ICosFormIcon cosFormIcon){
        CosXmlService cosXmlService = null;
        try {
            cosXmlService = initCosXmlService(context);
        } catch (TheCosKeyIsAbnormalException e) {
            cosFormIcon.onError(e.getMessage());
        }

        String bucketName = "form-icon-1302729481"; //格式：BucketName-APPID;
        final GetBucketRequest getBucketRequest = new GetBucketRequest(bucketName);
        // 前缀匹配，用来规定返回的对象前缀地址
//        getBucketRequest.setPrefix("dir/");

        // 单次返回最大的条目数量，默认1000
        getBucketRequest.setMaxKeys(1000);

        cosXmlService.getBucketAsync(getBucketRequest, new CosXmlResultListener() {
            @Override
            public void onSuccess(CosXmlRequest request, CosXmlResult result) {
                GetBucketResult getBucketResult = (GetBucketResult) result;
                getBucketResult.printResult();

                List<ListBucket.Contents> ll = getBucketResult.listBucket.contentsList;

                List<Picture> images = new ArrayList<>();
                for (ListBucket.Contents contents : ll) {
                    StringBuilder ss = new StringBuilder("https://");
                    ss.append(getBucketResult.listBucket.name);
                    ss.append(".cos.");
                    ss.append("ap-beijing").append(".myqcloud.com/");
                    ss.append(contents.key);

//                    LogUtil.d("图片拼接后的地址：",ss.toString());
                    Picture image = new Picture();
                    LocalMedia localMedia = Picture.generateHttpAsLocalMedia(ss.toString());
                    localMedia.setFileName(contents.key);
                    images.add(image);
                }

                if (cosFormIcon != null) cosFormIcon.onResult(images);
//                LogUtil.d("cos返回的数据:",getBucketResult.printResult());
//                https://form-icon-1302729481.cos.ap-beijing.myqcloud.com/icon_01.png

                if (getBucketResult.listBucket.isTruncated) {
                    // 表示数据被截断，需要拉取下一页数据
                    GetBucketResult prevPageResult = getBucketResult;
                }
            }

            // 如果您使用 kotlin 语言来调用，请注意回调方法中的异常是可空的，否则不会回调 onFail 方法，即：
            // clientException 的类型为 CosXmlClientException?，serviceException 的类型为 CosXmlServiceException?
            @Override
            public void onFail(CosXmlRequest cosXmlRequest,
                               @Nullable CosXmlClientException clientException,
                               @Nullable CosXmlServiceException serviceException) {
                if (clientException != null) {
                    clientException.printStackTrace();
                } else {
                    serviceException.printStackTrace();
                }
            }
        });
    }

    @Override
    protected QCloudLifecycleCredentials fetchNewCredentials() {
        // 首先从您的临时密钥服务器获取包含了密钥信息的响应
        if (cosSts == null) {
            LogUtils.e("请先调用getSts()方法获取秘钥，再调用cos");
            return null;
        }
        // 然后解析响应，获取临时密钥信息
        String tmpSecretId = cosSts.secretId; // 临时密钥 SecretId
        String tmpSecretKey = cosSts.secretKey; // 临时密钥 SecretKey
        String sessionToken = cosSts.sessionToken; // 临时密钥 Token
        long expiredTime = cosSts.expiredTime;//临时密钥有效截止时间戳，单位是秒

        //建议返回服务器时间作为签名的开始时间，避免由于用户手机本地时间偏差过大导致请求过期
        // 返回服务器时间作为签名的起始时间
        long startTime = cosSts.serverTime; //临时密钥有效起始时间，单位是秒

        // 最后返回临时密钥信息对象
        return new SessionQCloudCredentials(tmpSecretId, tmpSecretKey,
                sessionToken, startTime, expiredTime);
    }

    private CosXmlService initCosXmlService(Context context) throws TheCosKeyIsAbnormalException {
        if (cosSts == null) {
            LogUtils.e("请先调用getSts()方法获取秘钥，再调用cos");
            throw new TheCosKeyIsAbnormalException(1000,"请先调用getSts()方法获 取秘钥，再调用cos");
        }

        // 然后解析响应，获取临时密钥信息
        String tmpSecretId = cosSts.secretId; // 临时密钥 SecretId
        String tmpSecretKey = cosSts.secretKey; // 临时密钥 SecretKey
        String sessionToken = cosSts.sessionToken; // 临时密钥 Token
        long expiredTime = cosSts.expiredTime;//临时密钥有效截止时间戳，单位是秒
        //建议返回服务器时间作为签名的开始时间，避免由于用户手机本地时间偏差过大导致请求过期
        // 返回服务器时间作为签名的起始时间
        long startTime = cosSts.serverTime; //临时密钥有效起始时间，单位是秒
        SessionQCloudCredentials sessionQCloudCredentials = new SessionQCloudCredentials(tmpSecretId, tmpSecretKey,
                sessionToken, startTime, expiredTime);

        // 存储桶所在地域简称，例如广州地区是 ap-guangzhou
        String region = COS_REGION;

        // 创建 CosXmlServiceConfig 对象，根据需要修改默认的配置参数
        CosXmlServiceConfig serviceConfig = new CosXmlServiceConfig.Builder()
                .setRegion(region)
                .isHttps(true) // 使用 HTTPS 请求, 默认为 HTTP 请求
                .builder();

        return new CosXmlService(context,serviceConfig);
    }

    private TransferManager initTransferManager(Context context) throws TheCosKeyIsAbnormalException {
        CosXmlService cosXmlService = initCosXmlService(context);
        // 初始化 TransferConfig，这里使用默认配置，如果需要定制，请参考 SDK 接口文档
        // 默认对大于或等于2M的文件自动进行分块上传，分块大小为1M，可以通过如下代码修改分块阈值
        TransferConfig transferConfig = new TransferConfig.Builder()
                // 设置启用分块上传的最小对象大小 默认为2M
                .setDivisionForUpload(2097152)
                // 设置分块上传时的分块大小 默认为1M
                .setSliceSizeForUpload(1048576)
                // 设置是否强制使用简单上传, 禁止分块上传
                .setForceSimpleUpload(false)
                .build();
        // 初始化 TransferManager
        return new TransferManager(cosXmlService,
                transferConfig);
    }

    public String getFileUrl(String bucket, String cosPath){
        return "https://" + bucket + ".cos." + COS_REGION + ".myqcloud.com" + cosPath;
    }

    /**
     * 通过本地文件绝对路径来上传文件
     *
     * @param context 上下文
     * @param bucket 存储桶 "examplebucket-1250000000"
     * @param cosPath 文件存放于存储桶上的位置 "exampleobject.txt"
     * @param srcPath 文件本地路径
     * @param uploadId 是否分片续传的uploadId，如果为空，则从头开始上传文件
     *
     */
    public void uploadFile(Context context,String bucket, String cosPath, String srcPath, String uploadId,CosUploadCallBack callBack){
        upLoad(context,bucket,cosPath,srcPath,uploadId,callBack);
    }

    public void uploadMultipleFile(Context context,String bucket,  List<Pair<String,String>> pairList ,CosUploadMultipleCallBack callBack){
        int allSum = pairList.size() - 1;
        for (int i = 0; i < pairList.size(); i++) {
            Pair<String,String> stringStringPair = pairList.get(i);
            int finalI = i;
            upLoad(context, bucket, stringStringPair.first, stringStringPair.second, null, new CosUploadCallBack() {
                @Override
                public void onSleep(double sleep) {
                    double v = finalI * 100 + sleep;
                    callBack.onSleep(v/allSum);
                }

                @Override
                public void onComplete(String name) {
                    callBack.onComplete(name,finalI);
                    if ( finalI >= allSum) {
                        callBack.onCompleteAll();
                    }
                }

                @Override
                public void onError(String error) {
                    callBack.onError(error);
                }
            });
        }
    }


    private void upLoad(Context context,String bucket, String cosPath, String srcPath, String uploadId,CosUploadCallBack callBack){
        TransferManager transferManager = null;
        COSXMLUploadTask cosxmlUploadTask = null;

        try {
            transferManager = initTransferManager(context);
            // 上传文件
            cosxmlUploadTask = transferManager.upload(bucket, cosPath,
                    srcPath, uploadId);
            if (cosxmlUploadTask == null) throw new TheCosKeyIsAbnormalException(1001,"COSXMLUploadTask获取失败！");
        } catch (TheCosKeyIsAbnormalException e) {
            callBack.onError(e.getMessage());
        }

        //设置初始化分块上传回调，用于获取uploadId (5.9.7版本以及后续版本支持)
        cosxmlUploadTask.setInitMultipleUploadListener(new InitMultipleUploadListener() {
            @Override
            public void onSuccess(InitiateMultipartUpload initiateMultipartUpload) {
                //用于下次续传上传的 uploadId
                String uploadId = initiateMultipartUpload.uploadId;
            }
        });
        //设置上传进度回调
        cosxmlUploadTask.setCosXmlProgressListener(new CosXmlProgressListener() {
            @Override
            public void onProgress(long complete, long target) {
                double sleep =  (double) complete /target * 100;
                callBack.onSleep(sleep);
            }
        });

        //设置返回结果回调
        cosxmlUploadTask.setCosXmlResultListener(new CosXmlResultListener() {
            @Override
            public void onSuccess(CosXmlRequest request, CosXmlResult result) {
                COSXMLUploadTask.COSXMLUploadTaskResult uploadResult = (COSXMLUploadTask.COSXMLUploadTaskResult) result;
                callBack.onComplete(cosPath);
            }

            @Override
            public void onFail(CosXmlRequest request,
                               @Nullable CosXmlClientException clientException,
                               @Nullable CosXmlServiceException serviceException) {
                if (clientException != null) {
                    callBack.onError(clientException.getMessage());
                } else if (serviceException != null){
                    callBack.onError(serviceException.getMessage());
                }
            }
        });
        //设置任务状态回调, 可以查看任务过程
        cosxmlUploadTask.setTransferStateListener(new TransferStateListener() {
            @Override
            public void onStateChanged(TransferState state) {
                // todo notify transfer state
            }
        });
    }


    /**
     * 删除
     * @param context 上下文
     * @param bucket 存储桶
     * @param cosPath 文件地址
     * @param callBack 回调
     */
    public void deleteFile(Context context,String bucket, String cosPath, CosDeleteCallBack callBack) {
        CosXmlService cosXmlService = null;
        try {
            cosXmlService = initCosXmlService(context);
        } catch (TheCosKeyIsAbnormalException e) {
            callBack.onError(e.getMessage());
        }

        if (cosXmlService == null) {
            callBack.onError("未获取到CosXmlService，删除失败");
            LogUtils.e("删除未获取到CosXmlService，获取失败");
            return ;
        }

        DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest(bucket, cosPath);
        cosXmlService.deleteObjectAsync(deleteObjectRequest, new CosXmlResultListener() {
                @Override
                public void onSuccess(CosXmlRequest cosXmlRequest, CosXmlResult result) {
                    DeleteObjectResult deleteObjectResult = (DeleteObjectResult) result;
                    callBack.onComplete(cosPath);
                }

                // 如果您使用 kotlin 语言来调用，请注意回调方法中的异常是可空的，否则不会回调 onFail 方法，即：
                // clientException 的类型为 CosXmlClientException?，serviceException 的类型为 CosXmlServiceException?
                @Override
                public void onFail(CosXmlRequest cosXmlRequest,
                                   @Nullable CosXmlClientException clientException,
                                   @Nullable CosXmlServiceException serviceException) {
                    if (clientException != null) {
                        callBack.onError(clientException.getMessage());
                    } else if (serviceException != null){
                        callBack.onError(serviceException.getMessage());
                    }
                }
            });
    }

    /**
     * 复制
     * @param context 上下文
     * @param sourceBucket 复制的源桶
     * @param sourceCosPath 复制的源文件路径
     * @param bucket 复制的目的桶名
     * @param cosPath 复制的目的文件路径
     */
    public void copy(Context context,String sourceBucket,String sourceCosPath,String bucket,String cosPath,CosCopyCallBack callBack) throws TheCosKeyIsAbnormalException {
        TransferManager transferManager = initTransferManager(context);

        String sourceRegion = COS_REGION; //源对象的存储桶所在的地域
        //构造源对象属性
        CopyObjectRequest.CopySourceStruct copySourceStruct =
                new CopyObjectRequest.CopySourceStruct(sourceBucket, sourceRegion, sourceCosPath);

        //复制对象
        COSXMLCopyTask cosxmlCopyTask = transferManager.copy(bucket, cosPath,
                copySourceStruct);

        //设置返回结果回调
        cosxmlCopyTask.setCosXmlResultListener(new CosXmlResultListener() {
            @Override
            public void onSuccess(CosXmlRequest request, CosXmlResult result) {
                COSXMLCopyTask.COSXMLCopyTaskResult copyResult =
                        (COSXMLCopyTask.COSXMLCopyTaskResult) result;
                callBack.onComplete(copyResult.accessUrl);
            }

            // 如果您使用 kotlin 语言来调用，请注意回调方法中的异常是可空的，否则不会回调 onFail 方法，即：
            // clientException 的类型为 CosXmlClientException?，serviceException 的类型为 CosXmlServiceException?
            @Override
            public void onFail(CosXmlRequest request,
                               @Nullable CosXmlClientException clientException,
                               @Nullable CosXmlServiceException serviceException) {
                if (clientException != null) {
                    callBack.onError(clientException.getMessage());
                } else if (serviceException != null){
                    callBack.onError(serviceException.getMessage());
                }
            }
        });
        //设置任务状态回调, 可以查看任务过程
        cosxmlCopyTask.setTransferStateListener(new TransferStateListener() {
            @Override
            public void onStateChanged(TransferState state) {
                // todo notify transfer state
            }
        });
    }



    public interface ICosFormIcon{
        void onResult(List<Picture> pictures);
        void onError(String error);
    }
}
